"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _vue = require("vue");
var _ui = require("../../ui");
var _xeUtils = _interopRequireDefault(require("xe-utils"));
var _vn = require("../../ui/src/vn");
var _dom = require("../../ui/src/dom");
var _loading = _interopRequireDefault(require("../../loading/src/loading"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
 * 生成节点的唯一主键
 */
function getNodeUniqueId() {
  return _xeUtils.default.uniqueId('node_');
}
var _default = exports.default = (0, _vue.defineComponent)({
  name: 'VxeTree',
  props: {
    data: Array,
    height: [String, Number],
    minHeight: {
      type: [String, Number],
      default: () => (0, _ui.getConfig)().tree.minHeight
    },
    loading: Boolean,
    loadingConfig: Object,
    accordion: {
      type: Boolean,
      default: () => (0, _ui.getConfig)().tree.accordion
    },
    childrenField: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.childrenField
    },
    valueField: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.valueField
    },
    keyField: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.keyField
    },
    parentField: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.parentField
    },
    titleField: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.titleField
    },
    hasChildField: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.hasChildField
    },
    // mapChildrenField: {
    //   type: String as PropType<VxeTreePropTypes.MapChildrenField>,
    //   default: () => getConfig().tree.mapChildrenField
    // },
    transform: Boolean,
    // 已废弃
    isCurrent: Boolean,
    // 已废弃
    isHover: Boolean,
    showLine: {
      type: Boolean,
      default: () => (0, _ui.getConfig)().tree.showLine
    },
    trigger: String,
    indent: {
      type: Number,
      default: () => (0, _ui.getConfig)().tree.indent
    },
    showRadio: {
      type: Boolean,
      default: () => (0, _ui.getConfig)().tree.showRadio
    },
    checkNodeKey: {
      type: [String, Number],
      default: () => (0, _ui.getConfig)().tree.checkNodeKey
    },
    radioConfig: Object,
    showCheckbox: {
      type: Boolean,
      default: () => (0, _ui.getConfig)().tree.showCheckbox
    },
    checkNodeKeys: {
      type: Array,
      default: () => (0, _ui.getConfig)().tree.checkNodeKeys
    },
    checkboxConfig: Object,
    nodeConfig: Object,
    lazy: Boolean,
    toggleMethod: Function,
    loadMethod: Function,
    showIcon: {
      type: Boolean,
      default: true
    },
    iconOpen: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.iconOpen
    },
    iconClose: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.iconClose
    },
    iconLoaded: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.iconLoaded
    },
    size: {
      type: String,
      default: () => (0, _ui.getConfig)().tree.size || (0, _ui.getConfig)().size
    }
  },
  emits: ['update:modelValue', 'update:checkNodeKey', 'update:checkNodeKeys', 'node-click', 'node-dblclick', 'current-change', 'radio-change', 'checkbox-change', 'load-success', 'load-error'],
  setup(props, context) {
    const {
      emit,
      slots
    } = context;
    const xID = _xeUtils.default.uniqueId();
    const {
      computeSize
    } = (0, _ui.useSize)(props);
    const refElem = (0, _vue.ref)();
    const reactData = (0, _vue.reactive)({
      currentNode: null,
      nodeMaps: {},
      selectRadioKey: props.checkNodeKey,
      treeList: [],
      treeExpandedMaps: {},
      treeExpandLazyLoadedMaps: {},
      selectCheckboxMaps: {},
      indeterminateCheckboxMaps: {}
    });
    const internalData = {};
    const refMaps = {
      refElem
    };
    const computeTitleField = (0, _vue.computed)(() => {
      return props.titleField || 'title';
    });
    const computeKeyField = (0, _vue.computed)(() => {
      return props.keyField || 'id';
    });
    const computeValueField = (0, _vue.computed)(() => {
      const keyField = computeKeyField.value;
      return props.valueField || keyField;
    });
    const computeParentField = (0, _vue.computed)(() => {
      return props.parentField || 'parentId';
    });
    const computeChildrenField = (0, _vue.computed)(() => {
      return props.childrenField || 'children';
    });
    const computeHasChildField = (0, _vue.computed)(() => {
      return props.hasChildField || 'hasChild';
    });
    const computeIsRowCurrent = (0, _vue.computed)(() => {
      const nodeOpts = computeNodeOpts.value;
      const {
        isCurrent
      } = nodeOpts;
      if (_xeUtils.default.isBoolean(isCurrent)) {
        return isCurrent;
      }
      return props.isCurrent;
    });
    const computeIsRowHover = (0, _vue.computed)(() => {
      const nodeOpts = computeNodeOpts.value;
      const {
        isHover
      } = nodeOpts;
      if (_xeUtils.default.isBoolean(isHover)) {
        return isHover;
      }
      return props.isHover;
    });
    const computeRadioOpts = (0, _vue.computed)(() => {
      return Object.assign({
        showIcon: true
      }, (0, _ui.getConfig)().tree.radioConfig, props.radioConfig);
    });
    const computeCheckboxOpts = (0, _vue.computed)(() => {
      return Object.assign({
        showIcon: true
      }, (0, _ui.getConfig)().tree.checkboxConfig, props.checkboxConfig);
    });
    const computeNodeOpts = (0, _vue.computed)(() => {
      return Object.assign({}, (0, _ui.getConfig)().tree.nodeConfig, props.nodeConfig);
    });
    const computeLoadingOpts = (0, _vue.computed)(() => {
      return Object.assign({}, (0, _ui.getConfig)().tree.loadingConfig, props.loadingConfig);
    });
    const computeTreeStyle = (0, _vue.computed)(() => {
      const {
        height,
        minHeight
      } = props;
      const stys = {};
      if (height) {
        stys.height = (0, _dom.toCssUnit)(height);
      }
      if (minHeight) {
        stys.minHeight = (0, _dom.toCssUnit)(minHeight);
      }
      return stys;
    });
    const computeMaps = {
      computeRadioOpts,
      computeCheckboxOpts,
      computeNodeOpts
    };
    const $xeTree = {
      xID,
      props,
      context,
      internalData,
      reactData,
      getRefMaps: () => refMaps,
      getComputeMaps: () => computeMaps
    };
    const getNodeId = node => {
      const valueField = computeValueField.value;
      const nodeid = _xeUtils.default.get(node, valueField);
      return _xeUtils.default.eqNull(nodeid) ? '' : encodeURIComponent(nodeid);
    };
    const isExpandByNode = node => {
      const {
        treeExpandedMaps
      } = reactData;
      const nodeid = getNodeId(node);
      return !!treeExpandedMaps[nodeid];
    };
    const isCheckedByRadioNodeId = nodeid => {
      const {
        selectRadioKey
      } = reactData;
      return selectRadioKey === nodeid;
    };
    const isCheckedByRadioNode = node => {
      return isCheckedByRadioNodeId(getNodeId(node));
    };
    const isCheckedByCheckboxNodeId = nodeid => {
      const {
        selectCheckboxMaps
      } = reactData;
      return !!selectCheckboxMaps[nodeid];
    };
    const isCheckedByCheckboxNode = node => {
      return isCheckedByCheckboxNodeId(getNodeId(node));
    };
    const isIndeterminateByCheckboxNodeid = nodeid => {
      const {
        indeterminateCheckboxMaps
      } = reactData;
      return !!indeterminateCheckboxMaps[nodeid];
    };
    const isIndeterminateByCheckboxNode = node => {
      return isIndeterminateByCheckboxNodeid(getNodeId(node));
    };
    const emitCheckboxMode = value => {
      emit('update:checkNodeKeys', value);
    };
    const emitRadioMode = value => {
      emit('update:checkNodeKey', value);
    };
    const setRadioNode = node => {
      if (node) {
        reactData.selectRadioKey = getNodeId(node);
      }
      return (0, _vue.nextTick)();
    };
    const setCheckboxNode = (nodeList, checked) => {
      if (nodeList) {
        if (!_xeUtils.default.isArray(nodeList)) {
          nodeList = [nodeList];
        }
        handleCheckedCheckboxNode(nodeList.map(item => getNodeId(item)), checked);
      }
      return (0, _vue.nextTick)();
    };
    const setCheckboxByNodeId = (nodeIds, checked) => {
      if (nodeIds) {
        if (!_xeUtils.default.isArray(nodeIds)) {
          nodeIds = [nodeIds];
        }
        handleCheckedCheckboxNode(nodeIds, checked);
      }
      return (0, _vue.nextTick)();
    };
    const handleCheckedCheckboxNode = (nodeIds, checked) => {
      const selectKeyMaps = Object.assign({}, reactData.selectCheckboxMaps);
      nodeIds.forEach(key => {
        if (checked) {
          selectKeyMaps[key] = true;
        } else if (selectKeyMaps[key]) {
          delete selectKeyMaps[key];
        }
      });
      reactData.selectCheckboxMaps = selectKeyMaps;
    };
    const updateCheckboxChecked = nodeIds => {
      const selectKeyMaps = {};
      if (nodeIds) {
        nodeIds.forEach(key => {
          selectKeyMaps[key] = true;
        });
      }
      reactData.selectCheckboxMaps = selectKeyMaps;
    };
    const handleSetExpand = (nodeid, expanded, expandedMaps) => {
      if (expanded) {
        if (!expandedMaps[nodeid]) {
          expandedMaps[nodeid] = true;
        }
      } else {
        if (expandedMaps[nodeid]) {
          delete expandedMaps[nodeid];
        }
      }
    };
    const dispatchEvent = (type, params, evnt) => {
      emit(type, (0, _ui.createEvent)(evnt, {
        $tree: $xeTree
      }, params));
    };
    const createNode = records => {
      const valueField = computeValueField.value;
      return Promise.resolve(records.map(obj => {
        const item = Object.assign({}, obj);
        let nodeid = getNodeId(item);
        if (!nodeid) {
          nodeid = getNodeUniqueId();
          _xeUtils.default.set(item, valueField, nodeid);
        }
        return item;
      }));
    };
    const treeMethods = {
      dispatchEvent,
      clearCurrentNode() {
        reactData.currentNode = null;
        return (0, _vue.nextTick)();
      },
      getCurrentNodeId() {
        const {
          currentNode
        } = reactData;
        if (currentNode) {
          return getNodeId(currentNode);
        }
        return null;
      },
      getCurrentNode() {
        const {
          currentNode,
          nodeMaps
        } = reactData;
        if (currentNode) {
          const nodeItem = nodeMaps[currentNode];
          if (nodeItem) {
            return nodeItem.item;
          }
        }
        return null;
      },
      setCurrentNodeId(nodeKey) {
        const {
          nodeMaps
        } = reactData;
        const nodeItem = nodeMaps[nodeKey];
        reactData.currentNode = nodeItem ? nodeItem.item : null;
        return (0, _vue.nextTick)();
      },
      setCurrentNode(node) {
        reactData.currentNode = node;
        return (0, _vue.nextTick)();
      },
      clearRadioNode() {
        reactData.selectRadioKey = null;
        return (0, _vue.nextTick)();
      },
      getRadioNodeId() {
        return reactData.selectRadioKey || null;
      },
      getRadioNode() {
        const {
          selectRadioKey,
          nodeMaps
        } = reactData;
        if (selectRadioKey) {
          const nodeItem = nodeMaps[selectRadioKey];
          if (nodeItem) {
            return nodeItem.item;
          }
        }
        return null;
      },
      setRadioNodeId(nodeKey) {
        reactData.selectRadioKey = nodeKey;
        return (0, _vue.nextTick)();
      },
      setRadioNode,
      setCheckboxNode,
      setCheckboxByNodeId,
      getCheckboxNodeIds() {
        const {
          selectCheckboxMaps
        } = reactData;
        return Object.keys(selectCheckboxMaps);
      },
      getCheckboxNodes() {
        const {
          nodeMaps,
          selectCheckboxMaps
        } = reactData;
        const list = [];
        _xeUtils.default.each(selectCheckboxMaps, (item, nodeid) => {
          const nodeItem = nodeMaps[nodeid];
          if (nodeItem) {
            list.push(nodeItem.item);
          }
        });
        return list;
      },
      clearCheckboxNode() {
        reactData.selectCheckboxMaps = {};
        return (0, _vue.nextTick)();
      },
      setAllCheckboxNode(checked) {
        const selectMaps = {};
        const childrenField = computeChildrenField.value;
        if (checked) {
          _xeUtils.default.eachTree(reactData.treeList, node => {
            const nodeid = getNodeId(node);
            selectMaps[nodeid] = true;
          }, {
            children: childrenField
          });
        }
        reactData.selectCheckboxMaps = selectMaps;
        return (0, _vue.nextTick)();
      },
      clearExpandNode() {
        return treeMethods.clearAllExpandNode();
      },
      clearAllExpandNode() {
        _xeUtils.default.each(reactData.nodeMaps, nodeItem => {
          nodeItem.treeLoaded = false;
        });
        reactData.treeExpandedMaps = {};
        return (0, _vue.nextTick)();
      },
      setExpandByNodeId(nodeids, expanded) {
        const expandedMaps = Object.assign({}, reactData.treeExpandedMaps);
        if (nodeids) {
          if (!_xeUtils.default.isArray(nodeids)) {
            nodeids = [nodeids];
          }
          nodeids.forEach(nodeid => {
            handleSetExpand(nodeid, expanded, expandedMaps);
          });
          reactData.treeExpandedMaps = expandedMaps;
        }
        return (0, _vue.nextTick)();
      },
      getExpandNodeIds() {
        const {
          treeExpandedMaps
        } = reactData;
        return Object.keys(treeExpandedMaps);
      },
      getExpandNodes() {
        const {
          nodeMaps,
          treeExpandedMaps
        } = reactData;
        const list = [];
        _xeUtils.default.each(treeExpandedMaps, (item, nodeid) => {
          const nodeItem = nodeMaps[nodeid];
          if (nodeItem) {
            list.push(nodeItem.item);
          }
        });
        return list;
      },
      setExpandNode(nodes, expanded) {
        const expandedMaps = Object.assign({}, reactData.treeExpandedMaps);
        if (nodes) {
          if (!_xeUtils.default.isArray(nodes)) {
            nodes = [nodes];
          }
          nodes.forEach(node => {
            const nodeid = getNodeId(node);
            handleSetExpand(nodeid, expanded, expandedMaps);
          });
          reactData.treeExpandedMaps = expandedMaps;
        }
        return (0, _vue.nextTick)();
      },
      toggleExpandByNodeId(nodeids) {
        const expandedMaps = Object.assign({}, reactData.treeExpandedMaps);
        if (nodeids) {
          if (!_xeUtils.default.isArray(nodeids)) {
            nodeids = [nodeids];
          }
          nodeids.forEach(nodeid => {
            handleSetExpand(nodeid, !expandedMaps[nodeid], expandedMaps);
          });
          reactData.treeExpandedMaps = expandedMaps;
        }
        return (0, _vue.nextTick)();
      },
      toggleExpandNode(nodes) {
        const expandedMaps = Object.assign({}, reactData.treeExpandedMaps);
        if (nodes) {
          if (!_xeUtils.default.isArray(nodes)) {
            nodes = [nodes];
          }
          nodes.forEach(node => {
            const nodeid = getNodeId(node);
            handleSetExpand(nodeid, !expandedMaps[nodeid], expandedMaps);
          });
          reactData.treeExpandedMaps = expandedMaps;
        }
        return (0, _vue.nextTick)();
      },
      setAllExpandNode(expanded) {
        const expandedMaps = {};
        const childrenField = computeChildrenField.value;
        if (expanded) {
          _xeUtils.default.eachTree(reactData.treeList, node => {
            const childList = _xeUtils.default.get(node, childrenField);
            const hasChild = childList && childList.length;
            if (hasChild) {
              const nodeid = getNodeId(node);
              expandedMaps[nodeid] = true;
            }
          }, {
            children: childrenField
          });
        }
        reactData.treeExpandedMaps = expandedMaps;
        return (0, _vue.nextTick)();
      },
      reloadExpandNode(node) {
        const {
          lazy
        } = props;
        if (lazy) {
          treeMethods.clearExpandLoaded(node);
          return handleAsyncTreeExpandChilds(node);
        }
        return (0, _vue.nextTick)();
      },
      clearExpandLoaded(node) {
        const {
          lazy
        } = props;
        const {
          nodeMaps
        } = reactData;
        if (lazy) {
          const nodeItem = nodeMaps[getNodeId(node)];
          if (nodeItem) {
            nodeItem.treeLoaded = false;
          }
        }
        return (0, _vue.nextTick)();
      },
      /**
       * 用于树结构，给行数据加载子节点
       */
      loadChildrenNode(node, childRecords) {
        const {
          lazy,
          transform
        } = props;
        const {
          nodeMaps
        } = reactData;
        if (!lazy) {
          return Promise.resolve([]);
        }
        const childrenField = computeChildrenField.value;
        const parentNodeItem = nodeMaps[getNodeId(node)];
        const parentLevel = parentNodeItem ? parentNodeItem.level : 0;
        const parentNodes = parentNodeItem ? parentNodeItem.nodes : [];
        return createNode(childRecords).then(nodeList => {
          _xeUtils.default.eachTree(nodeList, (childRow, index, items, path, parent, nodes) => {
            const itemNodeId = getNodeId(childRow);
            nodeMaps[itemNodeId] = {
              item: node,
              itemIndex: -1,
              items,
              parent: parent || parentNodeItem.item,
              nodes: parentNodes.concat(nodes),
              level: parentLevel + nodes.length,
              lineCount: 0,
              treeLoaded: false
            };
          }, {
            children: childrenField
          });
          node[childrenField] = nodeList;
          if (transform) {
            node[childrenField] = nodeList;
          }
          updateNodeLine(node);
          return nodeList;
        });
      },
      isExpandByNode,
      isCheckedByRadioNodeId,
      isCheckedByRadioNode,
      isCheckedByCheckboxNodeId,
      isIndeterminateByCheckboxNode,
      isCheckedByCheckboxNode
    };
    const cacheNodeMap = () => {
      const {
        treeList
      } = reactData;
      const valueField = computeValueField.value;
      const childrenField = computeChildrenField.value;
      const keyMaps = {};
      _xeUtils.default.eachTree(treeList, (item, itemIndex, items, path, parent, nodes) => {
        let nodeid = getNodeId(item);
        if (!nodeid) {
          nodeid = getNodeUniqueId();
          _xeUtils.default.set(item, valueField, nodeid);
        }
        keyMaps[nodeid] = {
          item,
          itemIndex,
          items,
          parent,
          nodes,
          level: nodes.length,
          lineCount: 0,
          treeLoaded: false
        };
      }, {
        children: childrenField
      });
      reactData.nodeMaps = keyMaps;
    };
    const updateData = list => {
      const {
        transform
      } = props;
      const keyField = computeKeyField.value;
      const parentField = computeParentField.value;
      const childrenField = computeChildrenField.value;
      if (transform) {
        reactData.treeList = _xeUtils.default.toArrayTree(list, {
          key: keyField,
          parentKey: parentField,
          mapChildren: childrenField
        });
      } else {
        reactData.treeList = list ? list.slice(0) : [];
      }
      cacheNodeMap();
    };
    const handleCountLine = (item, isRoot, nodeItem) => {
      const {
        treeExpandedMaps
      } = reactData;
      const childrenField = computeChildrenField.value;
      const nodeid = getNodeId(item);
      nodeItem.lineCount++;
      if (treeExpandedMaps[nodeid]) {
        _xeUtils.default.arrayEach(item[childrenField], (childItem, childIndex, childList) => {
          if (!isRoot || childIndex < childList.length - 1) {
            handleCountLine(childItem, false, nodeItem);
          }
        });
      }
    };
    const updateNodeLine = node => {
      const {
        nodeMaps
      } = reactData;
      if (node) {
        const nodeid = getNodeId(node);
        const nodeItem = nodeMaps[nodeid];
        if (nodeItem) {
          _xeUtils.default.lastArrayEach(nodeItem.nodes, childItem => {
            const nodeid = getNodeId(childItem);
            const nodeItem = nodeMaps[nodeid];
            if (nodeItem) {
              nodeItem.lineCount = 0;
              handleCountLine(childItem, true, nodeItem);
            }
          });
        }
      }
    };
    const handleNodeClickEvent = (evnt, node) => {
      const {
        showRadio,
        showCheckbox,
        trigger
      } = props;
      const radioOpts = computeRadioOpts.value;
      const checkboxOpts = computeCheckboxOpts.value;
      const isRowCurrent = computeIsRowCurrent.value;
      let triggerCurrent = false;
      let triggerRadio = false;
      let triggerCheckbox = false;
      let triggerExpand = false;
      if (isRowCurrent) {
        triggerCurrent = true;
        changeCurrentEvent(evnt, node);
      } else if (reactData.currentNode) {
        reactData.currentNode = null;
      }
      if (trigger === 'node') {
        triggerExpand = true;
        toggleExpandEvent(evnt, node);
      }
      if (showRadio && radioOpts.trigger === 'node') {
        triggerRadio = true;
        changeRadioEvent(evnt, node);
      }
      if (showCheckbox && checkboxOpts.trigger === 'node') {
        triggerCheckbox = true;
        changeCheckboxEvent(evnt, node);
      }
      dispatchEvent('node-click', {
        node,
        triggerCurrent,
        triggerRadio,
        triggerCheckbox,
        triggerExpand
      }, evnt);
    };
    const handleNodeDblclickEvent = (evnt, node) => {
      dispatchEvent('node-dblclick', {
        node
      }, evnt);
    };
    const handleAsyncTreeExpandChilds = node => {
      const checkboxOpts = computeCheckboxOpts.value;
      const {
        loadMethod
      } = props;
      const {
        checkStrictly
      } = checkboxOpts;
      return new Promise(resolve => {
        if (loadMethod) {
          const tempExpandLazyLoadedMaps = Object.assign({}, reactData.treeExpandLazyLoadedMaps);
          const {
            nodeMaps
          } = reactData;
          const nodeid = getNodeId(node);
          const nodeItem = nodeMaps[nodeid];
          tempExpandLazyLoadedMaps[nodeid] = true;
          reactData.treeExpandLazyLoadedMaps = tempExpandLazyLoadedMaps;
          Promise.resolve(loadMethod({
            $tree: $xeTree,
            node
          })).then(childRecords => {
            const {
              treeExpandLazyLoadedMaps
            } = reactData;
            nodeItem.treeLoaded = true;
            if (treeExpandLazyLoadedMaps[nodeid]) {
              treeExpandLazyLoadedMaps[nodeid] = false;
            }
            if (!_xeUtils.default.isArray(childRecords)) {
              childRecords = [];
            }
            if (childRecords) {
              return treeMethods.loadChildrenNode(node, childRecords).then(childRows => {
                const tempExpandedMaps = Object.assign({}, reactData.treeExpandedMaps);
                if (childRows.length && !tempExpandedMaps[nodeid]) {
                  tempExpandedMaps[nodeid] = true;
                }
                reactData.treeExpandedMaps = tempExpandedMaps;
                // 如果当前节点已选中，则展开后子节点也被选中
                if (!checkStrictly && treeMethods.isCheckedByCheckboxNodeId(nodeid)) {
                  handleCheckedCheckboxNode(childRows.map(item => getNodeId(item)), true);
                }
                updateNodeLine(node);
                dispatchEvent('load-success', {
                  node,
                  data: childRecords
                }, new Event('load-success'));
                return (0, _vue.nextTick)();
              });
            } else {
              updateNodeLine(node);
              dispatchEvent('load-success', {
                node,
                data: childRecords
              }, new Event('load-success'));
            }
          }).catch(e => {
            const {
              treeExpandLazyLoadedMaps
            } = reactData;
            nodeItem.treeLoaded = false;
            if (treeExpandLazyLoadedMaps[nodeid]) {
              treeExpandLazyLoadedMaps[nodeid] = false;
            }
            updateNodeLine(node);
            dispatchEvent('load-error', {
              node,
              data: e
            }, new Event('load-error'));
          }).finally(() => {
            return (0, _vue.nextTick)();
          });
        } else {
          resolve();
        }
      });
    };
    /**
     * 展开与收起树节点
     * @param nodeList
     * @param expanded
     * @returns
     */
    const handleBaseTreeExpand = (nodeList, expanded) => {
      const {
        lazy,
        accordion,
        toggleMethod
      } = props;
      const {
        nodeMaps,
        treeExpandLazyLoadedMaps
      } = reactData;
      const tempExpandedMaps = Object.assign({}, reactData.treeExpandedMaps);
      const childrenField = computeChildrenField.value;
      const hasChildField = computeHasChildField.value;
      const result = [];
      let validNodes = toggleMethod ? nodeList.filter(node => toggleMethod({
        $tree: $xeTree,
        expanded,
        node
      })) : nodeList;
      if (accordion) {
        validNodes = validNodes.length ? [validNodes[validNodes.length - 1]] : [];
        // 同一级只能展开一个
        const nodeid = getNodeId(validNodes[0]);
        const nodeItem = nodeMaps[nodeid];
        if (nodeItem) {
          nodeItem.items.forEach(item => {
            const itemNodeId = getNodeId(item);
            if (tempExpandedMaps[itemNodeId]) {
              delete tempExpandedMaps[itemNodeId];
            }
          });
        }
      }
      const expandNodes = [];
      if (expanded) {
        validNodes.forEach(item => {
          const itemNodeId = getNodeId(item);
          if (!tempExpandedMaps[itemNodeId]) {
            const nodeItem = nodeMaps[itemNodeId];
            const isLoad = lazy && item[hasChildField] && !nodeItem.treeLoaded && !treeExpandLazyLoadedMaps[itemNodeId];
            // 是否使用懒加载
            if (isLoad) {
              result.push(handleAsyncTreeExpandChilds(item));
            } else {
              if (item[childrenField] && item[childrenField].length) {
                tempExpandedMaps[itemNodeId] = true;
                expandNodes.push(item);
              }
            }
          }
        });
      } else {
        validNodes.forEach(item => {
          const itemNodeId = getNodeId(item);
          if (tempExpandedMaps[itemNodeId]) {
            delete tempExpandedMaps[itemNodeId];
            expandNodes.push(item);
          }
        });
      }
      reactData.treeExpandedMaps = tempExpandedMaps;
      expandNodes.forEach(updateNodeLine);
      return Promise.all(result);
    };
    const toggleExpandEvent = (evnt, node) => {
      const {
        lazy
      } = props;
      const {
        treeExpandedMaps,
        treeExpandLazyLoadedMaps
      } = reactData;
      const nodeid = getNodeId(node);
      const expanded = !treeExpandedMaps[nodeid];
      evnt.stopPropagation();
      if (!lazy || !treeExpandLazyLoadedMaps[nodeid]) {
        handleBaseTreeExpand([node], expanded);
      }
    };
    const handleNodeCheckboxStatus = (node, selectKeyMaps, indeterminateMaps) => {
      const childrenField = computeChildrenField.value;
      const childList = _xeUtils.default.get(node, childrenField);
      const nodeid = getNodeId(node);
      if (childList && childList.length) {
        let checkSome = false;
        let checkSize = 0;
        childList.forEach(childNode => {
          const childNodeid = getNodeId(childNode);
          const isChecked = selectKeyMaps[childNodeid];
          if (isChecked || indeterminateMaps[childNodeid]) {
            if (isChecked) {
              checkSize++;
            }
            checkSome = true;
          }
        });
        const checkAll = checkSize === childList.length;
        if (checkAll) {
          if (!selectKeyMaps[nodeid]) {
            selectKeyMaps[nodeid] = true;
          }
          if (indeterminateMaps[nodeid]) {
            delete indeterminateMaps[nodeid];
          }
        } else {
          if (selectKeyMaps[nodeid]) {
            delete selectKeyMaps[nodeid];
          }
          indeterminateMaps[nodeid] = checkSome;
        }
      } else {
        if (indeterminateMaps[nodeid]) {
          delete indeterminateMaps[nodeid];
        }
      }
    };
    const updateCheckboxStatus = () => {
      const {
        treeList
      } = reactData;
      const childrenField = computeChildrenField.value;
      const checkboxOpts = computeCheckboxOpts.value;
      const {
        checkStrictly
      } = checkboxOpts;
      if (!checkStrictly) {
        const selectKeyMaps = Object.assign({}, reactData.selectCheckboxMaps);
        const indeterminateMaps = {};
        _xeUtils.default.eachTree(treeList, (node, index, items, path, parent, nodes) => {
          const childList = _xeUtils.default.get(node, childrenField);
          if (!childList || !childList.length) {
            handleNodeCheckboxStatus(node, selectKeyMaps, indeterminateMaps);
          }
          if (index === items.length - 1) {
            for (let len = nodes.length - 2; len >= 0; len--) {
              const parentItem = nodes[len];
              handleNodeCheckboxStatus(parentItem, selectKeyMaps, indeterminateMaps);
            }
          }
        });
        reactData.selectCheckboxMaps = selectKeyMaps;
        reactData.indeterminateCheckboxMaps = indeterminateMaps;
      }
    };
    const changeCheckboxEvent = (evnt, node) => {
      evnt.preventDefault();
      evnt.stopPropagation();
      const checkboxOpts = computeCheckboxOpts.value;
      const {
        checkStrictly,
        checkMethod
      } = checkboxOpts;
      let isDisabled = !!checkMethod;
      if (checkMethod) {
        isDisabled = !checkMethod({
          node
        });
      }
      if (isDisabled) {
        return;
      }
      const selectKeyMaps = Object.assign({}, reactData.selectCheckboxMaps);
      const childrenField = computeChildrenField.value;
      const nodeid = getNodeId(node);
      let isChecked = false;
      if (selectKeyMaps[nodeid]) {
        delete selectKeyMaps[nodeid];
      } else {
        isChecked = true;
        selectKeyMaps[nodeid] = isChecked;
      }
      if (!checkStrictly) {
        _xeUtils.default.eachTree(_xeUtils.default.get(node, childrenField), childNode => {
          const childNodeid = getNodeId(childNode);
          if (isChecked) {
            if (!selectKeyMaps[childNodeid]) {
              selectKeyMaps[childNodeid] = true;
            }
          } else {
            if (selectKeyMaps[childNodeid]) {
              delete selectKeyMaps[childNodeid];
            }
          }
        }, {
          children: childrenField
        });
      }
      reactData.selectCheckboxMaps = selectKeyMaps;
      updateCheckboxStatus();
      const value = Object.keys(reactData.selectCheckboxMaps);
      emitCheckboxMode(value);
      dispatchEvent('checkbox-change', {
        node,
        value,
        checked: isChecked
      }, evnt);
    };
    const changeCurrentEvent = (evnt, node) => {
      evnt.preventDefault();
      const nodeOpts = computeNodeOpts.value;
      const {
        currentMethod,
        trigger
      } = nodeOpts;
      const childrenField = computeChildrenField.value;
      const childList = _xeUtils.default.get(node, childrenField);
      const hasChild = childList && childList.length;
      let isDisabled = !!currentMethod;
      if (trigger === 'child') {
        if (hasChild) {
          return;
        }
      } else if (trigger === 'parent') {
        if (!hasChild) {
          return;
        }
      }
      if (currentMethod) {
        isDisabled = !currentMethod({
          node
        });
      }
      if (isDisabled) {
        return;
      }
      const isChecked = true;
      reactData.currentNode = node;
      dispatchEvent('current-change', {
        node,
        checked: isChecked
      }, evnt);
    };
    const changeRadioEvent = (evnt, node) => {
      evnt.preventDefault();
      evnt.stopPropagation();
      const radioOpts = computeRadioOpts.value;
      const {
        checkMethod
      } = radioOpts;
      let isDisabled = !!checkMethod;
      if (checkMethod) {
        isDisabled = !checkMethod({
          node
        });
      }
      if (isDisabled) {
        return;
      }
      const isChecked = true;
      const value = getNodeId(node);
      reactData.selectRadioKey = value;
      emitRadioMode(value);
      dispatchEvent('radio-change', {
        node,
        value,
        checked: isChecked
      }, evnt);
    };
    const treePrivateMethods = {};
    Object.assign($xeTree, treeMethods, treePrivateMethods);
    const renderRadio = (node, nodeid, isChecked) => {
      const {
        showRadio
      } = props;
      const radioOpts = computeRadioOpts.value;
      const {
        showIcon,
        checkMethod,
        visibleMethod
      } = radioOpts;
      const isVisible = !visibleMethod || visibleMethod({
        node
      });
      let isDisabled = !!checkMethod;
      if (showRadio && showIcon && isVisible) {
        if (checkMethod) {
          isDisabled = !checkMethod({
            node
          });
        }
        return (0, _vue.h)('div', {
          class: ['vxe-tree--radio-option', {
            'is--checked': isChecked,
            'is--disabled': isDisabled
          }],
          onClick: evnt => {
            if (!isDisabled) {
              changeRadioEvent(evnt, node);
            }
          }
        }, [(0, _vue.h)('span', {
          class: ['vxe-radio--icon', isChecked ? (0, _ui.getIcon)().RADIO_CHECKED : (0, _ui.getIcon)().RADIO_UNCHECKED]
        })]);
      }
      return (0, _vue.createCommentVNode)();
    };
    const renderCheckbox = (node, nodeid, isChecked) => {
      const {
        showCheckbox
      } = props;
      const checkboxOpts = computeCheckboxOpts.value;
      const {
        showIcon,
        checkMethod,
        visibleMethod
      } = checkboxOpts;
      const isIndeterminate = isIndeterminateByCheckboxNodeid(nodeid);
      const isVisible = !visibleMethod || visibleMethod({
        node
      });
      let isDisabled = !!checkMethod;
      if (showCheckbox && showIcon && isVisible) {
        if (checkMethod) {
          isDisabled = !checkMethod({
            node
          });
        }
        return (0, _vue.h)('div', {
          class: ['vxe-tree--checkbox-option', {
            'is--checked': isChecked,
            'is--indeterminate': isIndeterminate,
            'is--disabled': isDisabled
          }],
          onClick: evnt => {
            if (!isDisabled) {
              changeCheckboxEvent(evnt, node);
            }
          }
        }, [(0, _vue.h)('span', {
          class: ['vxe-checkbox--icon', isIndeterminate ? (0, _ui.getIcon)().CHECKBOX_INDETERMINATE : isChecked ? (0, _ui.getIcon)().CHECKBOX_CHECKED : (0, _ui.getIcon)().CHECKBOX_UNCHECKED]
        })]);
      }
      return (0, _vue.createCommentVNode)();
    };
    const renderNode = node => {
      const {
        lazy,
        showRadio,
        showCheckbox,
        showLine,
        indent,
        iconOpen,
        iconClose,
        iconLoaded,
        showIcon
      } = props;
      const {
        nodeMaps,
        treeExpandedMaps,
        currentNode,
        selectRadioKey,
        treeExpandLazyLoadedMaps
      } = reactData;
      const childrenField = computeChildrenField.value;
      const titleField = computeTitleField.value;
      const hasChildField = computeHasChildField.value;
      const childList = _xeUtils.default.get(node, childrenField);
      const hasChild = childList && childList.length;
      const titleSlot = slots.title;
      const extraSlot = slots.extra;
      const nodeid = getNodeId(node);
      const isExpand = treeExpandedMaps[nodeid];
      const nodeItem = nodeMaps[nodeid];
      const nodeValue = _xeUtils.default.get(node, titleField);
      const childVns = [];
      if (hasChild && treeExpandedMaps[nodeid]) {
        if (showLine) {
          childVns.push((0, _vue.h)('div', {
            key: 'line',
            class: 'vxe-tree--node-child-line',
            style: {
              height: `calc(${nodeItem.lineCount} * var(--vxe-ui-tree-node-height) - var(--vxe-ui-tree-node-height) / 2)`,
              left: `${(nodeItem.level + 1) * (indent || 1)}px`
            }
          }));
        }
        childList.forEach(childItem => {
          childVns.push(renderNode(childItem));
        });
      }
      let isRadioChecked = false;
      if (showRadio) {
        // eslint-disable-next-line eqeqeq
        isRadioChecked = nodeid == selectRadioKey;
      }
      let isCheckboxChecked = false;
      if (showCheckbox) {
        isCheckboxChecked = isCheckedByCheckboxNodeId(nodeid);
      }
      let hasLazyChilds = false;
      let isLazyLoading = false;
      let isLazyLoaded = false;
      if (lazy) {
        isLazyLoading = !!treeExpandLazyLoadedMaps[nodeid];
        hasLazyChilds = node[hasChildField];
        isLazyLoaded = !!nodeItem.treeLoaded;
      }
      return (0, _vue.h)('div', {
        class: ['vxe-tree--node-wrapper', `node--level-${nodeItem.level}`],
        nodeid
      }, [(0, _vue.h)('div', {
        class: ['vxe-tree--node-item', {
          'is--current': currentNode && nodeid === getNodeId(currentNode),
          'is-radio--checked': isRadioChecked,
          'is-checkbox--checked': isCheckboxChecked
        }],
        style: {
          paddingLeft: `${(nodeItem.level - 1) * (indent || 1)}px`
        },
        onClick(evnt) {
          handleNodeClickEvent(evnt, node);
        },
        onDblclick(evnt) {
          handleNodeDblclickEvent(evnt, node);
        }
      }, [showIcon || showLine ? (0, _vue.h)('div', {
        class: 'vxe-tree--node-item-switcher'
      }, showIcon && (lazy ? isLazyLoaded ? hasChild : hasLazyChilds : hasChild) ? [(0, _vue.h)('div', {
        class: 'vxe-tree--node-item-icon',
        onClick(evnt) {
          toggleExpandEvent(evnt, node);
        }
      }, [(0, _vue.h)('i', {
        class: isLazyLoading ? iconLoaded || (0, _ui.getIcon)().TREE_NODE_LOADED : isExpand ? iconOpen || (0, _ui.getIcon)().TREE_NODE_OPEN : iconClose || (0, _ui.getIcon)().TREE_NODE_CLOSE
      })])] : []) : (0, _vue.createCommentVNode)(), renderRadio(node, nodeid, isRadioChecked), renderCheckbox(node, nodeid, isCheckboxChecked), (0, _vue.h)('div', {
        class: 'vxe-tree--node-item-inner'
      }, [(0, _vue.h)('div', {
        class: 'vxe-tree--node-item-title'
      }, titleSlot ? (0, _vn.getSlotVNs)(titleSlot({
        node
      })) : `${nodeValue}`), extraSlot ? (0, _vue.h)('div', {
        class: 'vxe-tree--node-item-extra'
      }, (0, _vn.getSlotVNs)(extraSlot({
        node
      }))) : (0, _vue.createCommentVNode)()])]), hasChild && treeExpandedMaps[nodeid] ? (0, _vue.h)('div', {
        class: 'vxe-tree--node-child-wrapper'
      }, childVns) : (0, _vue.createCommentVNode)()]);
    };
    const renderNodeList = () => {
      const {
        treeList
      } = reactData;
      return (0, _vue.h)('div', {
        class: 'vxe-tree--node-list-wrapper'
      }, treeList.map(node => renderNode(node)));
    };
    const renderVN = () => {
      const {
        loading,
        trigger,
        showLine
      } = props;
      const vSize = computeSize.value;
      const radioOpts = computeRadioOpts.value;
      const checkboxOpts = computeCheckboxOpts.value;
      const treeStyle = computeTreeStyle.value;
      const loadingOpts = computeLoadingOpts.value;
      const isRowHover = computeIsRowHover.value;
      const loadingSlot = slots.loading;
      return (0, _vue.h)('div', {
        ref: refElem,
        class: ['vxe-tree', {
          [`size--${vSize}`]: vSize,
          'show--line': showLine,
          'checkbox--highlight': checkboxOpts.highlight,
          'radio--highlight': radioOpts.highlight,
          'node--hover': isRowHover,
          'node--trigger': trigger === 'node',
          'is--loading': loading
        }],
        style: treeStyle
      }, [renderNodeList(),
      /**
       * 加载中
       */
      (0, _vue.h)(_loading.default, {
        class: 'vxe-tree--loading',
        modelValue: loading,
        icon: loadingOpts.icon,
        text: loadingOpts.text
      }, loadingSlot ? {
        default: () => loadingSlot({
          $tree: $xeTree
        })
      } : {})]);
    };
    const dataFlag = (0, _vue.ref)(0);
    (0, _vue.watch)(() => props.data ? props.data.length : 0, () => {
      dataFlag.value++;
    });
    (0, _vue.watch)(() => props.data, () => {
      dataFlag.value++;
    });
    (0, _vue.watch)(dataFlag, () => {
      updateData(props.data || []);
    });
    (0, _vue.watch)(() => props.checkNodeKey, val => {
      reactData.selectRadioKey = val;
    });
    const checkboxFlag = (0, _vue.ref)(0);
    (0, _vue.watch)(() => props.checkNodeKeys ? props.checkNodeKeys.length : 0, () => {
      checkboxFlag.value++;
    });
    (0, _vue.watch)(() => props.checkNodeKeys, () => {
      checkboxFlag.value++;
    });
    (0, _vue.watch)(checkboxFlag, () => {
      updateCheckboxChecked(props.checkNodeKeys || []);
    });
    (0, _vue.onUnmounted)(() => {
      reactData.treeList = [];
      reactData.treeExpandedMaps = {};
      reactData.nodeMaps = {};
    });
    updateData(props.data || []);
    updateCheckboxChecked(props.checkNodeKeys || []);
    $xeTree.renderVN = renderVN;
    return $xeTree;
  },
  render() {
    return this.renderVN();
  }
});